/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hojano6;

/**
 *
 * @author Andrea Magaly Mendoza, 11331
 */
public class ImplementacionBinaryT <E extends Comparable<E>> extends AbstractBinaryTree <E>{
 
 
    
    //------------------------------------------------------------------------
    // Atributos:
    //------------------------------------------------------------------------
    
    //Valor asociado con el nodo.
    private E value;
    //Padre del nodo.
    private BinaryTree<E> parent;
    //Hijos del nodo.
    private BinaryTree<E> left, right;
    //El Ãºnico nodo vacio.
    protected static final BinaryTree EMPTY = new ImplementacionBinaryT();
    
    //------------------------------------------------------------------------
    // Constructores
    //------------------------------------------------------------------------

    /**
     * Constructor que permite la generaciÃ³n de un nodo vacio.
     * @pre: -
     * @post: Genera nodo vacio.
     */
    public ImplementacionBinaryT(){
        this.value=null;
        this.parent=null;
        this.left=this.right=this;
    }
    
    /**
     * Constructor que permite la generaciÃ³n de un Ã¡rbol con valor
     * y con hijos vacios.
     * @pre: El valor del Ã¡rbol no debe ser nulo.
     * @post: Regresa un Ã¡rbol con valor y dos subÃ¡rboles vacios.
     * @param value 
     */
    public ImplementacionBinaryT(E value){
        this.value=value;
        this.right=this.left= EMPTY;
    }

    /**
     * Constructor que permite la generaciÃ³n de un Ã¡rbol con valor
     * y con no hijos. 
     * @pre: El valor del Ã¡rbol no debe ser nulo.
     * @post: Regresa un Ã¡rbol con valor y dos subÃ¡rboles.
     * @param value
     * @param left
     * @param right 
     */
    public ImplementacionBinaryT(E value, BinaryTree<E> left, BinaryTree<E> right) {
        this.value = value;
        setRight(right);
        setLeft(left);
    }
    
    //------------------------------------------------------------------------
    // MÃ©todos
    //------------------------------------------------------------------------

    /**
     * Obtienen el subarbol derecho del nodo.
     * @pre: -
     * @post: Regresa la referencia de un (posible vacio) subÃ¡rbol
     * derecho.
     */
    @Override
    public BinaryTree<E> right() {
        return this.right;
    }

    /**
     * Obtiene el subarbol izquierdo del nodo.
     * @pre: -
     * @post: Regresa la referencia de un (posible vacio) subÃ¡rbol
     * izquierdo.
     */
    @Override
    public BinaryTree<E> left() {
        return this.left;
    }

    /**
     * Obtiene la referencia del padre del nodo.
     * @pre: -
     * @post: Regresa la referencia a un nodo padre o un nulo.
     */
    @Override
    public BinaryTree<E> parent() {
        return this.parent;
    }

    /**
     * Actualiza el subÃ¡rbol derecho del nodo.
     * @pre: -
     * @post: Coloca un subarbol derecho.
     * @param newRight 
     */
    @Override
    public void setRight(BinaryTree<E> newRight) {
        if (isEmpty()){
            return;
        }
        this.right=newRight;
        this.right.setParent(this);
    }

    /**
     * Actualiza el subÃ¡rbol izquierdo del nodo.
     * @pre: -
     * @post: Coloca un subarbol izquierdo.
     * @param newLeft 
     */
    @Override
    public void setLeft(BinaryTree<E> newLeft) {
        if (isEmpty()){
            return;
        }
        this.left = newLeft;
        left.setParent(this);
    }

     /**
      * Actualiza el padre del nodo.
      * @pre: -
      * @post: Vuelve a colocar un nuevo padre al nodo con el que se
      * estÃ¡ trabajando.
      * @param newParent 
      */
    @Override
    public void setParent(BinaryTree<E> newParent) {
        this.parent=newParent;
    }

    /**
     * MÃ©todo que genera un in-order iterador de los subÃ¡rboles.
     * @pre: -
     * @post: Regresa un in-order iterador de sus elementos.
     * @return in-order iterator.
     */
    @Override
    public Iterator iterator() {
        return new Iterator(this);
    }

    /**
     * Determina si el nodo es un hijo derecho.
     * @pre: -
     * @post: Retorna verdadero si es un hijo derecho del padre. 
     */
    @Override
    public boolean isRightChild() {
        if (parent()==null){
            return false;
        }
        else{
            return this == parent().right();
        }
    }

    /**
     * Determina si el nodo es un hijo izquierdo.
     * @pre: -
     * @post: Retorna verdadero si es un hijo izquierdo del padre. 
     */
    @Override
    public boolean isLeftChild() {
        if (parent()==null){
            return false;
        }
        else{
            return this==parent().left();
        }
    }

    /**
     * Retorna el valor asociado con el nodo.
     * @pre: -
     * @post: Retorna el valor asociado con el nodo con que se estÃ¡
     * trabajando.
     * @return value
     */
    @Override
    public E value() {
        return this.value;
    }

    /**
     * Determina el valor asociado con el nodo.
     * @pre: -
     * @post: Coloca el valor asociado con el nodo.
     * @param value 
     */
    @Override
    public void setValue(E value) {
        this.value=value;
    }

    /**
     * MÃ©todo que permite determinar si el Ã¡rbol estÃ¡ vacio.
     * @pre: -
     * @post: Regresa verdadero si el Ã¡rbol estÃ¡ vacio.
     */
    @Override
    public boolean isEmpty() {
        return this == EMPTY;
    }
    
    /**
     * Regresa el numero de descendientes del nodo.
     * @pre: -
     * @post: Regresa el tamaÃ±o del subÃ¡rbol.
     * @return size
     */
    @Override
    public int size(){
        if (isEmpty()){
            return 0;
        }
        else{
            return this.left().size() + this.right().size() +1;
        }
    }    
   
    
    
    
}
